/**
 * This class has methods for file manipulation.
 */
Ext.define('Ext.exporter.File', {
    singleton: true

    /**
     * Save a file locally using the content and name provided.
     *
     * Browser	compatibility:
     *
     * - Firefox 20+: max file size 800 MiB
     * - Chrome: max file size 345 MiB
     * - Chrome for Android: max file size n/a
     * - IE 10+: max file size 600 MiB
     * - IE < 10: Files are saved as text/html and max file size n/a
     * - Opera 15+: max file size 345 MiB
     * - Opera < 15: max file size n/a
     * - Safari 6.1+: max file size n/a; Blobs may be opened instead of saved sometimes—you may have
     * to direct your Safari users to manually press ⌘+S to save the file after it is opened.
     * Using the application/octet-stream MIME type to force downloads can cause issues in Safari.
     * - Safari < 6: max file size n/a
     *
     * @method saveAs
     * @param {String} content File content
     * @param {String} filename Name of the file including the extension
     * @param {String} [charset="UTF-8"] File's charset
     */

}, function(File){
    /* FileSaver.js
     *  A saveAs() & saveTextAs() FileSaver implementation.
     *  2014-06-24
     *
     *  Modify by Brian Chen
     *  Author: Eli Grey, http://eligrey.com
     *  License: X11/MIT
     *    See https://github.com/eligrey/FileSaver.js/blob/master/LICENSE.md
     */

    /*global self */
    /*jslint bitwise: true, indent: 4, laxbreak: true, laxcomma: true, smarttabs: true, plusplus: true */

    /*! @source http://purl.eligrey.com/github/FileSaver.js/blob/master/FileSaver.js */
    var navigator = window.navigator,
        saveAs = window.saveAs
            // IE 10+ (native saveAs)
            || (typeof navigator !== "undefined" &&
            navigator.msSaveOrOpenBlob && navigator.msSaveOrOpenBlob.bind(navigator))
            // Everyone else
            || (function (view) {
                "use strict";
                // IE <10 is explicitly unsupported
                if (typeof navigator !== "undefined" &&
                    /MSIE [1-9]\./.test(navigator.userAgent)) {
                    return;
                }
                var
                    doc = view.document
                // only get URL when necessary in case Blob.js hasn't overridden it yet
                    , get_URL = function () {
                        return view.URL || view.webkitURL || view;
                    }
                    , save_link = doc.createElementNS("http://www.w3.org/1999/xhtml", "a")
                    , can_use_save_link = !view.externalHost && "download" in save_link
                    , click = function (node) {
                        var event = doc.createEvent("MouseEvents");
                        event.initMouseEvent(
                            "click", true, false, view, 0, 0, 0, 0, 0
                            , false, false, false, false, 0, null
                        );
                        node.dispatchEvent(event);
                    }
                    , webkit_req_fs = view.webkitRequestFileSystem
                    , req_fs = view.requestFileSystem || webkit_req_fs || view.mozRequestFileSystem
                    , throw_outside = function (ex) {
                        (view.setImmediate || view.setTimeout)(function () {
                            throw ex;
                        }, 0);
                    }
                    , force_saveable_type = "application/octet-stream"
                    , fs_min_size = 0
                    , deletion_queue = []
                    , process_deletion_queue = function () {
                        var i = deletion_queue.length;
                        while (i--) {
                            var file = deletion_queue[i];
                            if (typeof file === "string") { // file is an object URL
                                get_URL().revokeObjectURL(file);
                            } else { // file is a File
                                file.remove();
                            }
                        }
                        deletion_queue.length = 0; // clear queue
                    }
                    , dispatch = function (filesaver, event_types, event) {
                        event_types = [].concat(event_types);
                        var i = event_types.length;
                        while (i--) {
                            var listener = filesaver["on" + event_types[i]];
                            if (typeof listener === "function") {
                                try {
                                    listener.call(filesaver, event || filesaver);
                                } catch (ex) {
                                    throw_outside(ex);
                                }
                            }
                        }
                    }
                    , FileSaver = function (blob, name) {
                        // First try a.download, then web filesystem, then object URLs
                        var
                            filesaver = this
                            , type = blob.type
                            , blob_changed = false
                            , object_url
                            , target_view
                            , get_object_url = function () {
                                var object_url = get_URL().createObjectURL(blob);
                                deletion_queue.push(object_url);
                                return object_url;
                            }
                            , dispatch_all = function () {
                                dispatch(filesaver, "writestart progress write writeend".split(" "));
                            }
                        // on any filesys errors revert to saving with object URLs
                            , fs_error = function () {
                                // don't create more object URLs than needed
                                if (blob_changed || !object_url) {
                                    object_url = get_object_url(blob);
                                }
                                if (target_view) {
                                    target_view.location.href = object_url;
                                } else {
                                    window.open(object_url, "_blank");
                                }
                                filesaver.readyState = filesaver.DONE;
                                dispatch_all();
                            }
                            , abortable = function (func) {
                                return function () {
                                    if (filesaver.readyState !== filesaver.DONE) {
                                        return func.apply(this, arguments);
                                    }
                                };
                            }
                            , create_if_not_found = { create: true, exclusive: false }
                            , slice
                            ;
                        filesaver.readyState = filesaver.INIT;
                        if (!name) {
                            name = "download";
                        }
                        if (can_use_save_link) {
                            object_url = get_object_url(blob);
                            save_link.href = object_url;
                            save_link.download = name;
                            click(save_link);
                            filesaver.readyState = filesaver.DONE;
                            dispatch_all();
                            return;
                        }
                        // Object and web filesystem URLs have a problem saving in Google Chrome when
                        // viewed in a tab, so I force save with application/octet-stream
                        // http://code.google.com/p/chromium/issues/detail?id=91158
                        if (view.chrome && type && type !== force_saveable_type) {
                            slice = blob.slice || blob.webkitSlice;
                            blob = slice.call(blob, 0, blob.size, force_saveable_type);
                            blob_changed = true;
                        }
                        // Since I can't be sure that the guessed media type will trigger a download
                        // in WebKit, I append .download to the filename.
                        // https://bugs.webkit.org/show_bug.cgi?id=65440
                        if (webkit_req_fs && name !== "download") {
                            name += ".download";
                        }
                        if (type === force_saveable_type || webkit_req_fs) {
                            target_view = view;
                        }
                        if (!req_fs) {
                            fs_error();
                            return;
                        }
                        fs_min_size += blob.size;
                        req_fs(view.TEMPORARY, fs_min_size, abortable(function (fs) {
                            fs.root.getDirectory("saved", create_if_not_found, abortable(function (dir) {
                                var save = function () {
                                    dir.getFile(name, create_if_not_found, abortable(function (file) {
                                        file.createWriter(abortable(function (writer) {
                                            writer.onwriteend = function (event) {
                                                target_view.location.href = file.toURL();
                                                deletion_queue.push(file);
                                                filesaver.readyState = filesaver.DONE;
                                                dispatch(filesaver, "writeend", event);
                                            };
                                            writer.onerror = function () {
                                                var error = writer.error;
                                                if (error.code !== error.ABORT_ERR) {
                                                    fs_error();
                                                }
                                            };
                                            "writestart progress write abort".split(" ").forEach(function (event) {
                                                writer["on" + event] = filesaver["on" + event];
                                            });
                                            writer.write(blob);
                                            filesaver.abort = function () {
                                                writer.abort();
                                                filesaver.readyState = filesaver.DONE;
                                            };
                                            filesaver.readyState = filesaver.WRITING;
                                        }), fs_error);
                                    }), fs_error);
                                };
                                dir.getFile(name, { create: false }, abortable(function (file) {
                                    // delete file if it already exists
                                    file.remove();
                                    save();
                                }), abortable(function (ex) {
                                    if (ex.code === ex.NOT_FOUND_ERR) {
                                        save();
                                    } else {
                                        fs_error();
                                    }
                                }));
                            }), fs_error);
                        }), fs_error);
                    }
                    , FS_proto = FileSaver.prototype
                    , saveAs = function (blob, name) {
                        return new FileSaver(blob, name);
                    }
                    ;
                FS_proto.abort = function () {
                    var filesaver = this;
                    filesaver.readyState = filesaver.DONE;
                    dispatch(filesaver, "abort");
                };
                FS_proto.readyState = FS_proto.INIT = 0;
                FS_proto.WRITING = 1;
                FS_proto.DONE = 2;

                FS_proto.error =
                    FS_proto.onwritestart =
                        FS_proto.onprogress =
                            FS_proto.onwrite =
                                FS_proto.onabort =
                                    FS_proto.onerror =
                                        FS_proto.onwriteend =
                                            null;

                view.addEventListener("unload", process_deletion_queue, false);
                saveAs.unload = function () {
                    process_deletion_queue();
                    view.removeEventListener("unload", process_deletion_queue, false);
                };
                return saveAs;
            }(
                typeof self !== "undefined" && self
                || typeof window !== "undefined" && window
                || this.content
            ));
// `self` is undefined in Firefox for Android content script context
// while `this` is nsIContentFrameMessageManager
// with an attribute `content` that corresponds to the window

    if (typeof module !== "undefined" && module !== null) {
        module.exports = saveAs;
    } else if ((typeof define !== "undefined" && define !== null) && (define.amd != null)) {
        define([], function () {
            return saveAs;
        });
    }

    var saveTextAs = window.saveTextAs
        || (function (textContent, fileName, charset) {
            fileName = fileName || 'download.txt';
            charset = charset || 'utf-8';
            textContent = (textContent || '').replace(/\r?\n/g, "\r\n");
            if (saveAs && Blob) {
                var blob = new Blob([textContent], { type: "text/plain;charset=" + charset });
                saveAs(blob, fileName);
                return true;
            } else {//IE9-
                var saveTxtWindow = window.frames.saveTxtWindow;
                if (!saveTxtWindow) {
                    saveTxtWindow = document.createElement('iframe');
                    saveTxtWindow.id = 'saveTxtWindow';
                    saveTxtWindow.style.display = 'none';
                    document.body.insertBefore(saveTxtWindow, null);
                    saveTxtWindow = window.frames.saveTxtWindow;
                    if (!saveTxtWindow) {
                        saveTxtWindow = window.open('', '_temp', 'width=100,height=100');
                        if (!saveTxtWindow) {
                            window.alert('Sorry, download file could not be created.');
                            return false;
                        }
                    }
                }

                var doc = saveTxtWindow.document;
                doc.open('text/html', 'replace');
                doc.charset = charset;
                if ( Ext.String.endsWith(fileName, '.htm', true) || Ext.String.endsWith(fileName, '.html', true) ) {
                    doc.close();
                    doc.body.innerHTML = '\r\n' + textContent + '\r\n';
                } else {
                    if (!Ext.String.endsWith(fileName, '.txt', true)) fileName += '.txt';
                    doc.write(textContent);
                    doc.close();
                }

                var retValue = doc.execCommand('SaveAs', null, fileName);
                saveTxtWindow.close();
                return retValue;
            }
        })

    File.saveAs = saveTextAs;
});